package com.whiteape.book.core.parser;

import com.whiteape.book.core.manager.ParserManager;
import com.whiteape.book.model.bo.ChapterContentBo;
import com.whiteape.book.model.dto.CollectionMediaBean;
import com.whiteape.book.model.dto.MediaChapterBean;
import com.whiteape.book.model.dto.SiteSourceBean;
import com.whiteape.book.net.RetrofitHelper;
import com.whiteape.book.utils.EncodeUtils;
import com.whiteape.book.utils.LogUtils;
import com.whiteape.book.utils.MD5Utils;
import com.whiteape.book.utils.URLUtils;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import io.reactivex.Single;
import okhttp3.RequestBody;

public class ChapterContentParser {

    private static List<ChapterContentBo> parseBookContent(SiteSourceBean siteSourceBean, String currentUrl, String html) {
        List<ChapterContentBo> result = new ArrayList<>();
        try {
            String contentListRule = siteSourceBean.getContentInfoRule().getContentList();
            String contentRule = siteSourceBean.getContentInfoRule().getContent();

            if (!StringUtils.isEmpty(contentListRule)) {
                List list = ParserManager.getElementList(currentUrl, html, contentListRule);
                if (list == null || list.size() == 0) {
                    return result;
                }

                int partNum = 0;
                for (Object ele : list) {
                    String doc = ele.toString();
                    ChapterContentBo contentBo = new ChapterContentBo();
                    String content = ParserManager.parseOne(currentUrl, doc, contentRule, new HashMap<>());
                    contentBo.setContent(com.whiteape.book.utils.StringUtils.formatHtml(content));
                    contentBo.setCurPartNum(partNum++);
                    contentBo.setPartTotal(list.size());
                    result.add(contentBo);
                }
            } else {
                String content = ParserManager.parseOne(currentUrl, html, contentRule, new HashMap<>());
                ChapterContentBo contentBo = new ChapterContentBo();
                contentBo.setContent(com.whiteape.book.utils.StringUtils.formatHtml(content));
                result.add(contentBo);
            }
            return result;

        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    public static Single<List<ChapterContentBo>> parseBook(SiteSourceBean siteSourceBean, String chapterDetailUrl, String html) {

        if (siteSourceBean == null || StringUtils.isEmpty(html)) {
            return Single.create(emitter -> emitter.onError(new Throwable("args check error")));
        }
        String pageTotalRule = siteSourceBean.getContentInfoRule().getPageTotal();
        String pageNextRule = siteSourceBean.getContentInfoRule().getPageNext();

        int pageTotalTemp = -1;

        //TODO 为了省事不改太多接口，这里的varMap是临时做的，并不是collectionMediaBean里面的
        //TODO 也就是说用不了其他地方注入的参数（当然，这种情况应该几乎用不上才是)
        HashMap<String, String> varMap = new HashMap<>();
        if (!StringUtils.isEmpty(pageTotalRule)) {
            pageTotalTemp = Integer.parseInt(ParserManager.parseOne(chapterDetailUrl, html, pageTotalRule, varMap));
        }
        final int pageTotal = pageTotalTemp;
        if (pageTotal > 0) {
            pageAdd(pageTotal, varMap);
        }
        //小说中不包括pageLinkList(这个给图源做单个页面单张图片的懒加载用的)
        //TODO
        return Single.create(emitter -> {
            try {
                if (!StringUtils.isEmpty(pageNextRule)) {
                    //如果pageTotal不是空，那么表示nextPage可能需要用到这里的page进行迭代
                    List<ChapterContentBo> contentBoList = parseBookContent(siteSourceBean, chapterDetailUrl, html);
                    String nextPage = ParserManager.parseOne(chapterDetailUrl, html, pageNextRule, varMap);
                    while (!StringUtils.isEmpty(nextPage)) {
                        nextPage = URLUtils.getAbsolutePath(chapterDetailUrl, nextPage);
                        String tmpHtml = requestPage(siteSourceBean, nextPage);
                        List<ChapterContentBo> tmpList = parseBookContent(siteSourceBean, nextPage, tmpHtml);
                        if (tmpList == null || tmpList.isEmpty()) {
                            break;
                        }
                        contentBoList.addAll(tmpList);
                        //page ++
                        if (!pageAdd(pageTotal, varMap)) {
                            break;
                        }
                        String prePage = nextPage;
                        nextPage = ParserManager.parseOne(chapterDetailUrl, tmpHtml, pageNextRule, varMap);
                        if (StringUtils.isEmpty(nextPage)) {
                            break;
                        }
                    }
                    emitter.onSuccess(contentBoList);

                } else {
                    emitter.onSuccess(parseBookContent(siteSourceBean, chapterDetailUrl, html));
                }
            } catch (Exception e) {
                LogUtils.e("parseComic err 2" + e.getLocalizedMessage());
                emitter.onError(e);
            }


        });
    }


    /**
     * 漫画的主要问题是：1. 图片藏在js里面，那么需要content是$JS.的
     * 2. 一个章节对应多个page link，一个page link对应一张图
     *
     * @param siteSourceBean
     * @param
     * @param html
     * @return
     */
    public static Single<List<ChapterContentBo>> parseComic(SiteSourceBean
                                                                    siteSourceBean, CollectionMediaBean collectionMediaBean, MediaChapterBean
                                                                    chapter, String html) {
        if (siteSourceBean == null || StringUtils.isEmpty(html)) {
            return Single.create(emitter -> emitter.onError(new Throwable("args check error")));
        }
        String chapterId = chapter.getId();
        String chapterDetailUrl = chapter.getLink();

//        String chapterDetailUrl = mediaChapterBean.getLink();
//        String chapterId = mediaChapterBean.getId();

//        Document doc = Jsoup.parse(html);
//        System.out.println(html);
        //TODO 还有content分页情况
        List<ChapterContentBo> result = new ArrayList<>();
        String pageLinkListRule = siteSourceBean.getContentInfoRule().getPageLinkList();
        String pageTotalRule = siteSourceBean.getContentInfoRule().getPageTotal();
        String pageNextRule = siteSourceBean.getContentInfoRule().getPageNext();

        int pageTotalTemp = -1;
        try {

            //如果是懒加载，这里的chapterDetailUrl 实际上是一个章节下具体的某一页的页面链接
            //那么只需要parseOnePageLink即可
//            if (lazy) {
//                return parseOnePageLink(html, chapterId, contentListRule, contentRule);
//            }
            if (!StringUtils.isEmpty(pageTotalRule)) {
//                pageTotalTemp = Integer.parseInt(JsoupSelectorEngine.checkAndParse(doc, pageTotalRule));
                pageTotalTemp = Integer.parseInt(ParserManager.parseOne(chapterDetailUrl, html, pageTotalRule, collectionMediaBean.getVarMap()));
            }
            final int pageTotal = pageTotalTemp;
            //多个page，并且每个page只有一张图才这样
            //lazy loading的每个只有一个图片来占位
            //TODO 多个页面，每个页面多个图怎么办?
            //pageLinkList和pageNext只能有其中一个
            //pageLinkList表示一个页面对应一张图
            //pageNext表示可能大于1张图
            if (!StringUtils.isEmpty(pageLinkListRule)) {
                //如果pageLinkList不为空
//                if (pageLinkListRule.startsWith("@JS:")) {
                return Single.create(emitter -> {
                            try {
//                            List<String> linkList = JSEngine.checkAndParsePageLink(pageLinkListRule, chapterDetailUrl, doc.html(), pageTotal);
//                            List linkList = JSEngine.getElementList(chapterDetailUrl, doc.html(), pageLinkListRule, pageTotal);
                                List linkList = ParserManager.getElementList(chapterDetailUrl, html, pageLinkListRule, pageTotal, collectionMediaBean.getVarMap());
                                for (int i = 0; i < linkList.size(); i++) {
                                    ChapterContentBo bo = new ChapterContentBo();

                                    bo.setHeaders(siteSourceBean.getContentInfoRule().getHeaders());
                                    if (bo.getHeaders() != null) {
                                        for (Map.Entry<String, String> entry : bo.getHeaders().entrySet()) {
                                            bo.getHeaders().put(entry.getKey(), ParserManager.parseOne(chapterDetailUrl, html, entry.getValue(), collectionMediaBean.getVarMap(), true));
                                        }
                                    } else{
                                        bo.setHeaders(new HashMap<>());
                                        bo.getHeaders().put("Referer", siteSourceBean.getSiteHostUrl());
                                    }
                                    if(!bo.getHeaders().containsKey("Referer") && !bo.getHeaders().containsKey("referer")){
                                        bo.getHeaders().put("Referer", siteSourceBean.getSiteHostUrl());
                                    }
//                                    bo.setReferer(URLUtils.getAbsolutePath(siteSourceBean.getSiteHostUrl(), chapterDetailUrl));
                                    bo.setChapterId(chapterId);
                                    bo.setPartTotal(linkList.size());
                                    bo.setLazyLoading(true);
                                    bo.setCurPartNum(i);
                                    // TODO check List return type
                                    bo.setContent(ParserManager.getElementString(linkList.get(i)));
                                    result.add(bo);
                                }
                                emitter.onSuccess(result);
                            } catch (Exception e) {
                                e.printStackTrace();
                                LogUtils.e("JS引擎解析出现错误，需要重试");
                                emitter.onError(e);
                            }


                        }
                );

//                }
            } else if (!StringUtils.isEmpty(pageNextRule)) {
                return Single.create(emitter -> {
                    try {

                        //如果pageTotal不是空，那么表示nextPage可能需要用到这里的page进行迭代
                        HashMap<String, String> varMap = collectionMediaBean.getVarMap();
                        if (pageTotal > 0) {
                            pageAdd(pageTotal, varMap);
                        }

                        List<ChapterContentBo> contentBoList = parseOnePageLink(siteSourceBean, collectionMediaBean, chapter, html).blockingGet();
                        String nextPage = ParserManager.parseOne(chapterDetailUrl, html, pageNextRule, varMap);
                        while (!StringUtils.isEmpty(nextPage)) {
                            nextPage = URLUtils.getAbsolutePath(chapterDetailUrl, nextPage);
                            String tmpHtml = requestPage(siteSourceBean, nextPage);
                            List<ChapterContentBo> tmpList = parseOnePageLink(siteSourceBean, collectionMediaBean, chapter, tmpHtml).blockingGet();
                            if (tmpList == null || tmpList.isEmpty()) {
                                break;
                            }
                            contentBoList.addAll(tmpList);
                            //page ++
                            if (!pageAdd(pageTotal, varMap)) {
                                break;
                            }

                            nextPage = ParserManager.parseOne(nextPage, tmpHtml, pageNextRule, varMap);

                        }
                        int partNum = 0;
                        int total = contentBoList.size();
                        for (ChapterContentBo contentBo : contentBoList) {
                            contentBo.setCurPartNum(partNum++);
                            contentBo.setPartTotal(total);
                        }
                        emitter.onSuccess(contentBoList);

                    } catch (Exception e) {
                        LogUtils.e("parseComic err 2" + e.getLocalizedMessage());
                    }
                });

            }
        } catch (Exception e) {
            e.printStackTrace();
        }


//        return parseOnePageLink(chapterDetailUrl, html, chapterId, contentListRule, contentRule);
        return parseOnePageLink(siteSourceBean, collectionMediaBean, chapter, html);

    }

    private static boolean pageAdd(int pageTotal, HashMap<String, String> varMap) {
        //如果本身就没有page，那么不能终止循环
        if(pageTotal <= 0){
            return true;
        }
        if (pageTotal > 0) {
            int nextPageInt = 0;
            //有pageTotal，可能会用到page
            String currentPageStr = "1";
            if (varMap.containsKey("page")) {
                currentPageStr = varMap.get("page");
            }
            if (!StringUtils.isEmpty(currentPageStr)) {
                int currentPageInt = Integer.parseInt(currentPageStr);
                if (currentPageInt < pageTotal) {
                    nextPageInt = currentPageInt + 1;
                } else {
                    return false;
                }
            }
            varMap.put("page", "" + nextPageInt);
            return true;
        }
        return false;
    }

    private static String requestPage(SiteSourceBean siteSourceBean, String link) {
        Map<String, String> headerMap = new HashMap<>();
//        headerMap.put("User-Agent", "Mozilla/5.0 (Linux; U; Android 8.0.0; zh-CN; MHA-AL00 Build/HUAWEIMHA-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/40.0.2214.89 UCBrowser/11.6.4.950 UWS/2.11.1.50 Mobile Safari/537.36 AliApp(DingTalk/4.5.8) com.alibaba.android.rimet/10380049 Channel/227200 language/zh-CN");
        if (!StringUtils.isEmpty(siteSourceBean.getUserAgent())) {
            headerMap.put("User-Agent", siteSourceBean.getUserAgent());
        }
        headerMap.put("Referer", siteSourceBean.getSiteHostUrl());
        String content;
        String charset = siteSourceBean.getSearch().getCharset();
        try {
            if (link.toUpperCase().contains("@POST:")) {
                //是post请求的
                String[] arr = link.split("(?i)@POST:");
                String url = arr[0];
                String body = arr[1];
                RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("text/plain"), body);

                //用bytes获取原始字节，然后转化为对应编码的string
                content = new String(RetrofitHelper.getInstance().getHttpApiImpl(siteSourceBean.getSiteHostUrl())
                        .postDirectly(url, headerMap, requestBody)
                        .execute().body().bytes(), charset);


            } else {
                content = new String(RetrofitHelper.getInstance().getHttpApiImpl(siteSourceBean.getSiteHostUrl())
                        .getDirectly(link, headerMap)
                        .execute().body().bytes(), charset);
            }
//            Set<String> utf8Set = new HashSet<>();
//            utf8Set.add("utf-8");
//            utf8Set.add("utf8");
//            //TODO 默认为不是utf8的就是gbk?
//            if (!utf8Set.contains(charset.toLowerCase())) {
//                content = EncodeUtils.getUTF8StringFromGBKString(content);
//            }
            return content;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 对于一般的MediaChapterBean，正常获取，非lazy,无curPartNum
     *
     * @param siteSourceBean
     * @param collectionMediaBean
     * @param chapter
     * @param html
     * @return
     */
    private static Single<List<ChapterContentBo>> parseOnePageLink(SiteSourceBean
                                                                           siteSourceBean, CollectionMediaBean collectionMediaBean, MediaChapterBean
                                                                           chapter, String html) {
//        return parseOnePageLink(curLink, html, chapterId, 0, contentListRule, contentRule);
        String curLink = chapter.getLink();
        String chapterId = chapter.getId();
        return parseOnePageLink(siteSourceBean, collectionMediaBean, chapterId, curLink, html, 0);
    }


    public static Single<List<ChapterContentBo>> parseOnePageLink(SiteSourceBean
                                                                          siteSourceBean, CollectionMediaBean collectionMediaBean, ChapterContentBo
                                                                          chapterBo, String html) {
        String curLink = chapterBo.getContent();
        String chapterId = chapterBo.getChapterId();
        int curPartNum = chapterBo.getCurPartNum();
        return parseOnePageLink(siteSourceBean, collectionMediaBean, chapterId, curLink, html, curPartNum);
    }

    public static Single<List<ChapterContentBo>> parseOnePageLinkLazy(SiteSourceBean
                                                                              siteSourceBean, CollectionMediaBean collectionMediaBean, ChapterContentBo
                                                                              chapterContentBo, String html) {
        return parseOnePageLink(siteSourceBean, collectionMediaBean, chapterContentBo, html);
    }


    /**
     * 每一个页面中，处理content
     *
     * @param html
     * @return
     */
    public static Single<List<ChapterContentBo>> parseOnePageLink(SiteSourceBean
                                                                          siteSourceBean, CollectionMediaBean collectionMediaBean, String chapterId, String
                                                                          curLink, String html, int curPartNum) {
        String contentListRule = siteSourceBean.getContentInfoRule().getContentList();
        String contentRule = siteSourceBean.getContentInfoRule().getContent();
//        Document doc = Jsoup.parse(html);

        List<ChapterContentBo> result = new ArrayList<>();
        Single<List<ChapterContentBo>> observable = Single.create(emitter -> {
            try {
                if (!StringUtils.isEmpty(contentListRule)) {
//                    Elements list = doc.select(contentListRule);
                    List list = ParserManager.getElementList(curLink, html, contentListRule, 1, collectionMediaBean.getVarMap());
                    if (list == null || list.size() == 0) {
                        emitter.onSuccess(result);
//                        emitter.onComplete();
                        return;
                    }

                    int partNum = 0;
                    for (Object contentEle : list) {
                        ChapterContentBo contentBo = new ChapterContentBo();
//                        String content = checkAndParse(contentEle, contentRule);
                        String eleStr = ParserManager.getElementString(contentEle);
                        String content = ParserManager.parseOne(curLink, eleStr, contentRule, collectionMediaBean.getVarMap());
                        contentBo.setHeaders(siteSourceBean.getContentInfoRule().getHeaders());
                        if (contentBo.getHeaders() != null) {
                            for (Map.Entry<String, String> entry : contentBo.getHeaders().entrySet()) {
                                contentBo.getHeaders().put(entry.getKey(), ParserManager.parseOne(curLink, html, entry.getValue(), collectionMediaBean.getVarMap(), true));
                            }
                        } else{
                            contentBo.setHeaders(new HashMap<>());
                            contentBo.getHeaders().put("Referer", siteSourceBean.getSiteHostUrl());
                        }
                        if(!contentBo.getHeaders().containsKey("Referer") && !contentBo.getHeaders().containsKey("referer")){
                            contentBo.getHeaders().put("Referer", siteSourceBean.getSiteHostUrl());
                        }
//                        contentBo.setReferer(URLUtils.getAbsolutePath(siteSourceBean.getSiteHostUrl(), curLink));
                        contentBo.setChapterId(chapterId);
                        contentBo.setContent(content);
                        contentBo.setCurPartNum(partNum++);
                        contentBo.setLazyLoading(false);
                        contentBo.setPartTotal(list.size());
                        result.add(contentBo);
                    }
                } else {

                    String content;
//                    if (contentRule.startsWith("$JS.")) {
//
//                        content = JSEngine.checkAndParseContent(contentRule, doc.html());
//                    } else {
//
//                        content = checkAndParse(doc.body(), contentRule);
//                    }

                    content = ParserManager.parseOne(curLink, html, contentRule, collectionMediaBean.getVarMap());
                    String[] urls = content.split(",");
                    int partNum = curPartNum;
                    for (String url : urls) {
                        url = URLUtils.getAbsolutePath(curLink, url);
                        ChapterContentBo contentBo = new ChapterContentBo();
                        contentBo.setChapterId(chapterId);
                        contentBo.setHeaders(siteSourceBean.getContentInfoRule().getHeaders());
                        if (contentBo.getHeaders() != null) {
                            for (Map.Entry<String, String> entry : contentBo.getHeaders().entrySet()) {
                                contentBo.getHeaders().put(entry.getKey(), ParserManager.parseOne(curLink, html, entry.getValue(), collectionMediaBean.getVarMap(), true));
                            }
                        } else{
                            contentBo.setHeaders(new HashMap<>());
                            contentBo.getHeaders().put("Referer", siteSourceBean.getSiteHostUrl());
                        }

                        if(!contentBo.getHeaders().containsKey("Referer") && !contentBo.getHeaders().containsKey("referer")){
                            contentBo.getHeaders().put("Referer", siteSourceBean.getSiteHostUrl());
                        }
//                        contentBo.setReferer(URLUtils.getAbsolutePath(siteSourceBean.getSiteHostUrl(),curLink));
                        contentBo.setContent(url);
                        contentBo.setLazyLoading(false);
                        contentBo.setCurPartNum(partNum++);
                        contentBo.setPartTotal(urls.length);
                        result.add(contentBo);
                    }

                }


                emitter.onSuccess(result);
//                emitter.onComplete();

//            emitter.onComplete();
            } catch (Exception e) {
                e.printStackTrace();
                emitter.onError(e);
//                emitter.onComplete();
            }

        });

        return observable;

    }


}
